/*
 * Copyright (c) 2025 Industrial Software Feature Database
 */
package com.comac.ins.bomt.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.comac.ins.bomt.domain.DetailStrengthV2Bom;
import com.comac.ins.bomt.domain.vo.*;
import com.comac.ins.bomt.service.BomFileParseServiceV2;
import com.comac.ins.common.core.domain.model.LoginUser;
import com.comac.ins.common.biz.exception.BizException;
import com.comac.ins.common.biz.utils.BizAssertUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
 * @author zhanghongyi
 * @date 2024/8/28
 * @description BomFileParserUtil
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class BomFileParseServiceV2Impl implements BomFileParseServiceV2 {
    @Value("${bom.original.headerRowNo:7}")
    private Integer originalBomHeaderRowNo;

    @Value("${bom.codePath.joinChar:,}")
    private String fullCodePathJoinChar;

    /**
     * 解析原始装机清单
     */
    @Override
    public List<DetailOriginalV2BomVo> parseOrigin(File file) {
        List<DetailOriginalV2BomVo> parseResult = EasyExcel.read(file).headRowNumber(originalBomHeaderRowNo).head(DetailOriginalV2BomVo.class).autoCloseStream(false).sheet().doReadSync();
        BizAssertUtil.isFalse(CollectionUtils.isEmpty(parseResult) ||
            StringUtils.isBlank(parseResult.get(0).getName()) ||
            StringUtils.isBlank(parseResult.get(0).getLevel()) ||
            StringUtils.isBlank(parseResult.get(0).getCnt()) ||
            StringUtils.isBlank(parseResult.get(0).getSection()) ||
            StringUtils.isBlank(parseResult.get(0).getVersion()) ||
            StringUtils.isBlank(parseResult.get(0).getCode()), "please check original bom xlsx is right");
        Stack<DetailOriginalV2BomVo> parentStack = new Stack<>();
        AtomicLong ord = new AtomicLong();
        for (DetailOriginalV2BomVo detailOriginalV2BomVo : parseResult) {
            if (CollectionUtils.isNotEmpty(parentStack) && Integer.parseInt(detailOriginalV2BomVo.getLevel()) <= Integer.parseInt(parentStack.peek().getLevel())) {
                int curLevel = Integer.parseInt(detailOriginalV2BomVo.getLevel());
                while (CollectionUtils.isNotEmpty(parentStack) && Integer.parseInt(parentStack.peek().getLevel()) >= curLevel) {
                    parentStack.pop();
                }
            }
            parentStack.push(detailOriginalV2BomVo);
            String fullCodePath = StringUtils.join(parentStack.stream().map(DetailOriginalV2BomVo::getCode).toList(), fullCodePathJoinChar);
            detailOriginalV2BomVo.setOrd(ord.getAndIncrement());
            detailOriginalV2BomVo.setFullCodePath(fullCodePath);
        }
        return parseResult;

    }

    /**
     * 解析标准装机清单
     */
    @Override
    public Map<String, List<DetailStandardV2BomVo>> parseStandard(LoginUser loginUser, File file, String aircraftModel, String track, String subTrack) {
        Map<String, List<DetailStandardV2BomVo>> result = new HashMap<>();
        try (FileInputStream fileInputStream = new FileInputStream(file);ZipInputStream zipInputStream = new ZipInputStream(fileInputStream, Charset.forName("GBK"))) {
            ZipEntry zipEntry = zipInputStream.getNextEntry();
            while (zipEntry != null) {
                String fileName = StringUtils.split(zipEntry.getName(), ".")[0];
                String[] tokes = StringUtils.split(fileName, "_");
                BizAssertUtil.isTrue(tokes.length == 3, "parse file name fail，check file name like 'C919_S50_标准装机清单.xlsx'");
                if (!zipEntry.isDirectory() && StringUtils.equals(tokes[2], "标准装机清单")) {
                    List<DetailStandardV2BomVo> parsedItemListAll = EasyExcel.read(zipInputStream).ignoreEmptyRow(true).excelType(ExcelTypeEnum.XLSX).headRowNumber(1).charset(StandardCharsets.UTF_8).head(DetailStandardV2BomVo.class).autoCloseStream(false).sheet().doReadSync();
                    Map<String, List<DetailStandardV2BomVo>> parsedItemListMap = parsedItemListAll.stream().collect(Collectors.groupingBy(DetailStandardV2BomVo::getSection));

                    for (Map.Entry<String, List<DetailStandardV2BomVo>> entry : parsedItemListMap.entrySet()) {
                        List<DetailStandardV2BomVo> parsedItemList = entry.getValue();
                        AtomicLong ord = new AtomicLong();
                        Stack<DetailStandardV2BomVo> parentStack = new Stack<>();
                        for (DetailStandardV2BomVo voItem : parsedItemList) {
                            if (CollectionUtils.isNotEmpty(parentStack) && Integer.parseInt(voItem.getLevel()) <= Integer.parseInt(parentStack.peek().getLevel())) {
                                int curLevel = Integer.parseInt(voItem.getLevel());
                                while (CollectionUtils.isNotEmpty(parentStack) && Integer.parseInt(parentStack.peek().getLevel()) >= curLevel) {
                                    parentStack.pop();
                                }
                            }
                            parentStack.push(voItem);
                            //填充主部段为部段
                            voItem.setMainSection(voItem.getSection());
                            voItem.setFullCodePath(StringUtils.join(parentStack.stream().map(DetailStandardV2BomVo::getCode).toList(), fullCodePathJoinChar));
                            voItem.setOrd(ord.getAndIncrement());
                            voItem.setAircraftModel(aircraftModel);
                            voItem.setGroupType(voItem.getMainSection());
                            voItem.setSubGroupType(voItem.getSection());
                            voItem.setTrack(track);
                            voItem.setSubTrack(subTrack);
                        }
                        result.put(entry.getKey(), parsedItemList);
                    }
                }
                zipEntry = zipInputStream.getNextEntry();
            }
            zipInputStream.closeEntry();
        } catch (IOException e) {
            throw new BizException(MessageFormat.format("parse standard bom fail:{0}", e.getMessage()));
        }
        return result;
    }

    /**
     * 解析强度数模清单
     */
    @Override
    public Map<String, List<DetailStrengthV2Bom>> parseStrength(LoginUser loginUser, File file, String aircraftModel, String track, String subTrack) {
        Map<String, List<DetailStrengthV2Bom>> result = new HashMap<>(10);
        try (FileInputStream fileInputStream = new FileInputStream(file);ZipInputStream zipInputStream = new ZipInputStream(fileInputStream, Charset.forName("GBK"))) {
            ZipEntry zipEntry = zipInputStream.getNextEntry();
            while (zipEntry != null) {
                String fileName = StringUtils.split(zipEntry.getName(), ".")[0];
                String[] tokes = StringUtils.split(fileName, "_");
                BizAssertUtil.isTrue(tokes.length == 3, "parse file name fail，check file name like 'C919_S50_强度数模清单.xlsx'");
                if (!zipEntry.isDirectory() && StringUtils.equals(tokes[2], "强度数模清单")) {
                    List<DetailStrengthBomImportVo> parsedItemList = EasyExcel.read(zipInputStream).ignoreEmptyRow(true).excelType(ExcelTypeEnum.XLSX).headRowNumber(1).charset(StandardCharsets.UTF_8).head(DetailStrengthBomImportVo.class).autoCloseStream(false).sheet().doReadSync();
                    AtomicLong ord = new AtomicLong();
                    Stack<DetailStrengthBomImportVo> parentStack = new Stack<>();

                    List<DetailStrengthV2Bom> modelList = new ArrayList<>();
                    for (DetailStrengthBomImportVo voItem : parsedItemList) {
                        while (CollectionUtils.isNotEmpty(parentStack) && (StringUtils.equals("1", voItem.getLevel()) || !StringUtils.equals("1", parentStack.peek().getLevel()))) {
                            parentStack.pop();
                        }
                        parentStack.push(voItem);
                        DetailStrengthV2Bom qbom = new DetailStrengthV2Bom();
                        modelList.add(qbom);
                        BeanUtils.copyProperties(voItem, qbom);
                        qbom.setFullCodePath(StringUtils.join(parentStack.stream().map(DetailStrengthBomImportVo::getCode).toList(), fullCodePathJoinChar));
                        qbom.setOrd(ord.getAndIncrement());
                        qbom.setAircraftModel(aircraftModel);
                        qbom.setGroupType(tokes[0]+"_"+tokes[1]);
                        qbom.setSubGroupType(null);
                        qbom.setTrack(track);
                        qbom.setSubTrack(subTrack);
                        Pair<String, String> versionAndNum = voItem.getVersionAndNum();
                        qbom.setVersionNum(versionAndNum.getRight());
                        qbom.setVersion(versionAndNum.getLeft());
                    }
                    result.put(tokes[0]+"_"+tokes[1], modelList);
                }
                zipEntry = zipInputStream.getNextEntry();
            }
            zipInputStream.closeEntry();
        } catch (IOException e) {
            throw new BizException(MessageFormat.format("parse strength bom fail:{0}", e.getMessage()));
        }
        return result;
    }
}
